package com.spzx.cart.service.impl;

import com.spzx.cart.api.domain.CartInfo;
import com.spzx.cart.service.CartInfoService;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.context.SecurityContextHolder;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.product.api.RemoteProductService;
import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.api.domain.SkuPriceVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author GAX
 * @date 2025-09-27
 */

@Service
public class CartInfoServiceImpl implements CartInfoService {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RemoteProductService remoteProductService;

    private String getCartKey(Long userId) {
        //定义 Redis 中的 key 为 user:userId:cart
        return "user:cart:" + userId;
    }

    @Override
    public void addToCart(Long skuId, Integer num) {
        // 判断购物车中是否有该商品
        Long userId = SecurityContextHolder.getUserId();
        String redisKey = this.getCartKey(userId);
        String field = skuId.toString();
        Boolean exists = redisTemplate.opsForHash().hasKey(redisKey, field);
        // 如果商品存在，则更新数量，单品数量的上限是 99
        if (exists) {
            CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(redisKey, field);
            Integer skuNum = cartInfo.getSkuNum();
            cartInfo.setSkuNum(skuNum + num > 99 ? 99 :skuNum + num);
            cartInfo.setUpdateTime(new Date());
            redisTemplate.opsForHash().put(redisKey, field, cartInfo);
        } else {
            // 如果商品不存在，则构建购物车商品对象，限制最多加购商品数量是 50 个，并保存到购物车中
            // 业务校验
            Long count = redisTemplate.opsForHash().size(redisKey);
            if (count > 50) {
                throw new RuntimeException("购物车中最多只能加入 50 个商品!");
            }
            // 远程调用商品微服务，获取商品信息
            R<ProductSku> result = remoteProductService.getProductSku(skuId, SecurityConstants.INNER);
            if (result.getCode() != 200) {
                throw new ServiceException("远程调用失败了，失败原因：" + result.getMsg());
            }
            ProductSku productSku = result.getData();
            // 构建购物车商品对象
            CartInfo cartInfo = new CartInfo();
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(productSku.getId());
            // 注意：这里的价格，在实际开发中，需要单独去数据库中再查一遍，保证最新的价格，而不是从缓存中拿的价格
            cartInfo.setCartPrice(productSku.getSalePrice());
            cartInfo.setSkuPrice(productSku.getSalePrice());
            cartInfo.setSkuNum(num > 99 ? 99 : num);
            cartInfo.setThumbImg(productSku.getThumbImg());
            cartInfo.setSkuName(productSku.getSkuName());
            cartInfo.setIsChecked(1);
            cartInfo.setCreateTime(new Date());
            // 将购物车商品写入 Redis
            redisTemplate.opsForHash().put(redisKey, field, cartInfo);
        }
    }

    @Override
    public List<CartInfo> cartList() {
        // ① 确定当前用户购物车的 key
        String cartKey = this.getCartKey(SecurityContextHolder.getUserId());
        // ② 获取购物车 Hash 结构中 Value 列表对应的就是购物车商品列表
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfoList = hashOps.values();
        // ③ 如果有值，则按照加入购物车时间进行降序，并返回
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            // 使用 stream 流进行排序
            List<CartInfo> collect = cartInfoList.stream()
                    // 降序
                    .sorted(((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime())))
                    .collect(Collectors.toList());
            return collect;
        }
        return null;
    }

    @Override
    public void checkCart(Long skuId, Integer isChecked) {
        // 确定当前用户购物车的 key
        String cartKey = this.getCartKey(SecurityContextHolder.getUserId());
        // 确定购物车上商品的 field
        String field = skuId.toString();
        // 先获取用户选择的商品
        BoundHashOperations<String, String, CartInfo> boundHashOps = redisTemplate.boundHashOps(cartKey);
        if (boundHashOps.hasKey(field)) {
            CartInfo cartInfoUp = boundHashOps.get(field);
            // cartInfoUp 写回缓存
            cartInfoUp.setIsChecked(isChecked);
            // 更新缓存
            boundHashOps.put(field, cartInfoUp);
        }
    }

    @Override
    public void allCheckCart(Integer isChecked) {
        // 获取当前登录用户的 id
        Long userId = SecurityContextHolder.getUserId();
        // 获取 Redis Key
        String cartKey = getCartKey(userId);
        // 创建 BoundHashOperations
        BoundHashOperations<String, String, CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        // 获取当前 Redis Key 对应的 Hash 中所有的 field 的 value
        List<CartInfo> cartInfoList = hashOperations.values();
        cartInfoList.forEach(elm -> {
            CartInfo cartInfo = hashOperations.get(elm.getSkuId().toString());
            cartInfo.setIsChecked(isChecked);
        });
    }

    @Override
    public void deleteCart(Long skuId) {
        // 确定当前用户购物车的 Key
        String cartKey = this.getCartKey(SecurityContextHolder.getUserId());
        // 创建 BoundHashOperations
        BoundHashOperations<String, String, CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        // 删除指定购物车商品
        String field = skuId.toString();
        Boolean exists = hashOperations.hasKey(field);
        if (exists) {
            hashOperations.delete(field);
        }
    }

    @Override
    public void clearCart() {
        // 获取当前登录用户的id
        Long userId = SecurityContextHolder.getUserId();
        String cartKey = getCartKey(userId);
        // 直接用 redisTemplate 删除整个 Redis Key 即可
        redisTemplate.delete(cartKey);
    }

    @Override
    public List<CartInfo> getCartCheckedList() {
        // 确定当前用户购物车的 Key
        String cartKey = this.getCartKey(SecurityContextHolder.getUserId());
        // 获取购物车 hash 结构中 value 列表，对应的就是购物车商品列表
        BoundHashOperations<String, String, CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        // 获取选中商品列表
        List<CartInfo> cartInfoList = hashOperations.values();
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            List<CartInfo> checkedInfoList = cartInfoList.stream()
                    // 过滤出选中的购物项
                    .filter(elm -> elm.getIsChecked() == 1)
                    .toList();
            return checkedInfoList;
        }
        return null;
    }

    @Override
    public Boolean updateCartPrice(Long userId) {
        // 根据用户 id，获取当前用户购物车的 key
        String cartKey = getCartKey(userId);
        // 获取 hash 结构，key-field-value
        BoundHashOperations<String, String, CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        // 获取购物项列表
        List<CartInfo> cartCachInfoList = hashOperations.values();
        if (!CollectionUtils.isEmpty(cartCachInfoList)) {
            for (CartInfo cartInfo : cartCachInfoList) {
                if (cartInfo.getIsChecked().intValue() == 1) {
                    // 远程调用商品服务，获取实时价格
                    R<SkuPriceVo> r = remoteProductService.getSkuPrice(cartInfo.getSkuId(), SecurityConstants.INNER);
                    if (r.getCode() == R.FAIL) {
                        throw new ServiceException("获取商品实时价格异常：" + r.getMsg());
                    }
                    // 将更新后的价格写入 Redis
                    SkuPriceVo skuPriceVo = r.getData();

                    // 更新放入购物车时价格
                    // cartInfo.setCartPrice(skuPriceVo.getSalePrice());

                    // 更新实时价格
                    cartInfo.setSkuPrice(skuPriceVo.getSalePrice());
                    // 更新 Redis 中购物车的 filed
                    hashOperations.put(cartInfo.getSkuId().toString(), cartInfo);
                }
            }
        }
        return true;
    }

    @Override
    public Boolean deleteCartCheckedList() {
        // 确定当前用户购物车的 key
        String cartKey = this.getCartKey(SecurityContextHolder.getUserId());
        // 获取购物车的 hash 结构
        BoundHashOperations<String, String, CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        // 获取 values
        List<CartInfo> cartInfoList = hashOperations.values();
        cartInfoList.stream().filter(cartInfo -> cartInfo.getIsChecked() == 1)
                .forEach(elm -> {
                    hashOperations.delete(elm.getSkuId().toString());
                });
        return true;
    }
}